home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 314_01 / mnpdrvr.c < prev    next >
C/C++ Source or Header  |  1990-05-14  |  22KB  |  889 lines

  1. /*=====================================================================
  2.  
  3.                       The Microcom MNP Library
  4.                         (Microsoft C Version)
  5.  
  6.     10/05/89 - lcb.lt_rsn++ fix in rcv_lt...gp
  7.     11/4/87 - explicit data typing...gp
  8.     8/27/87 - rcv_lt() modified to use lcb.lcl_credit..gp
  9.  
  10. -----------------------------------------------------------------------
  11.  
  12.         LDRIVER - MNP Link RS-232 Interrupt Service Routines
  13.  
  14.      This module implements asynchronous I/O for IBM PC-compatible
  15.      machines and thus much of this code may not be portable to 
  16.      other dissimilar environments.
  17.  
  18.      This code implements Class 2 of the MNP link protocol,
  19.      i.e. it uses the stop/start byte-oriented framing technique.
  20.      A Class 3 implementation is not possible in the IBM PC 
  21.      environment since the communications hardware is not capable
  22.      of switching to synchronous (bit-oriented) operation.
  23.      Protocol messages and procedures, however, are independent
  24.      of the framing technique.        
  25.  
  26.      Global routines:
  27.  
  28.     - ascode: service I/O interrupt 
  29.     - lne_stat: check carrier status 
  30.     - trigger_sf: initiate transmit interrupts
  31.  
  32. =====================================================================*/
  33.  
  34. /* Header files
  35. */
  36. #include <dos.h>
  37. #include <mnpdat.h>
  38.  
  39. /* Interrupt-related definitions
  40. */
  41. #define INT_8259A_PORT    0x20
  42. #define EOI        0x20
  43. #define RCV_DATA    4
  44. #define THR_EMPTY    2
  45. #define MODSTAT_CHNG    0
  46.  
  47. /* Send framer state names
  48. */
  49. #define SF_INIT     0
  50. #define SF_DLE        1
  51. #define SF_STX        2
  52. #define SF_INFO     3
  53. #define SF_DLEINFO    4
  54. #define SF_ETX        5
  55. #define SF_FCS1     6
  56. #define SF_FCS2     7
  57.  
  58. /* Receive framer state names
  59. */
  60. #define RF_INIT     0
  61. #define RF_DLE        1
  62. #define RF_STX        2
  63. #define RF_HDLEN    3
  64. #define RF_HEADER    4
  65. #define RF_INFOL    5
  66. #define RF_INFO     6
  67. #define RF_FCS1     7
  68. #define RF_FCS2     8
  69.  
  70. /* Frame octet definitions
  71. */
  72. #define SYN        0x16
  73. #define DLE        0x10
  74. #define ETX        3
  75. #define STX        2
  76.  
  77. /* Length of header buffer (maximum acceptable LPDU header)
  78. */
  79. #define MAX_HDRLEN    100
  80.  
  81. /* Bit set, clear and test definitions
  82. */
  83. #define SETBIT1(bit)    lcb.status_1 |= bit;       
  84. #define SETBIT2(bit)    lcb.status_2 |= bit;
  85. #define SETBIT3(bit)    lcb.status_3 |= bit;
  86. #define CLRBIT1(bit)    lcb.status_1 &= ~bit;         
  87. #define CLRBIT2(bit)    lcb.status_2 &= ~bit;
  88. #define CLRBIT3(bit)    lcb.status_3 &= ~bit;
  89. #define BIT1SET(bit)    (lcb.status_1 & bit)         
  90. #define BIT2SET(bit)    (lcb.status_2 & bit)
  91. #define BIT3SET(bit)    (lcb.status_3 & bit)
  92.  
  93. /* External references
  94. */
  95. extern USIGN_16 iir_add;            /* int id reg address */
  96. extern USIGN_8 linestat;            /* line status var */
  97. extern struct TIMERS tmr;
  98. extern struct link_ctl_blk lcb;  /* link control block */
  99. extern struct BUFFER rb, ftb, rlkb;  /* buffers */
  100. extern USIGN_8 *rb_iptr;        /* rcv buf insert pointer */
  101. extern USIGN_16 rb_cnt,tbcnt;        /* buffer counts */
  102. extern USIGN_8 rbuf[RBUF_LEN];    /* receive buffer */
  103.  
  104. /* Function definitions
  105. */
  106. void snd_framer();
  107. void rcv_framer();
  108. void mod_stat();
  109. void rcv_lt();
  110. void rcv_la();
  111. void rcv_lna();
  112. void rcv_ln();
  113.  
  114. /* Local data
  115. */
  116. USIGN_8 *sf_ptr,
  117.      *rf_hptr,
  118.      *rf_dptr;
  119. USIGN_8 snd_char,
  120.      rcv_char;
  121. struct 
  122.     {
  123.     USIGN_8 low;
  124.     USIGN_8 hi;
  125.     }
  126.         snd_fcs,            /* send fcs */
  127.           rcv_fcs,            /* calculated receive fcs */
  128.           rfcs;            /* received fcs */
  129. USIGN_16 rdle_flg;            /* 'previous char DLE' flag */
  130. USIGN_16 rf_hdrlen,            /* receive header length  */
  131.     hdrcnt,            
  132.     rf_datlen,
  133.     sf_state,                /* send framer state var */
  134.     rf_state,                /* receive framer state var */
  135.     sf_len,
  136.     sf_busy,                /* 'send frame' flag */
  137.     sf_lt,                /* 'sending LT' flag */
  138.     frame_snt,                /* 'info field sent' flag */ 
  139.     frame_rcvd,            /* 'frame received' flag */
  140.     frame_dne;                /* 'frame sent' flag */
  141. USIGN_8 *rf_tiptr;
  142.  
  143. struct MNP_CB *p_mnpcb;
  144. struct BLST *dat_struct, *hdr_struct;
  145.  
  146. USIGN_16 modem_out_busy;    /* RS-232 hardware status flag
  147.                               0=transmitter not active
  148.                               1=transmitter active */
  149.  
  150. /* Function declarations
  151. */
  152. USIGN_8 get_char();
  153.  
  154. /*GLOBAL***************************************************************
  155.  
  156.     ascode - MNP RS-232 interrupt service routine
  157.  
  158.      This routine is called by 'async' (in module 'async.asm')
  159.      to service an async I/O interrupt.
  160.  
  161. **********************************************************************/
  162.  
  163. ascode()
  164. {
  165.  
  166. USIGN_8 int_id_reg;            /* value in int id reg */
  167.  
  168. /* Handle interrupts for as long as there are any. 
  169. */
  170. for (;;)
  171.     {
  172.  
  173. /* Read the Interrupt Identification Register.  If bit 0 is on, 
  174. ** there is no interrupt.  In this case cancel the interrupt by writing ** the "end-of-interrupt" byte to the Oper Ctl Word 2 and return. 
  175. */
  176.     if ((int_id_reg = inp(iir_add)) & BIT0_ON)
  177.         {
  178.         outp(INT_8259A_PORT, EOI);
  179.         return;
  180.         }
  181.  
  182. /* Since bit 0 is off, there is an interrupt.  Take action based
  183. ** on the type of interrupt. 
  184. */
  185.     switch (int_id_reg)
  186.         {
  187.  
  188. /* Receive buffer full interrupt
  189. */
  190.         case RCV_DATA:                
  191.             rcv_framer();
  192.             if ((sf_busy == FALSE)
  193.                 || ((inp(iir_add + 3) & 0x20) == 0))
  194.                 break;
  195.  
  196. /* Transmit buffer empty interrupt
  197. */
  198.         case THR_EMPTY:
  199.             snd_framer();
  200.             break;
  201.  
  202. /* Modem status change interrupt
  203. */
  204.         case MODSTAT_CHNG:            
  205.             mod_stat();
  206.             break;
  207.         }
  208.     }
  209. }
  210.  
  211. /*GLOBAL***************************************************************
  212.  
  213.     lne_stat - physical-connection status routine
  214.  
  215. **********************************************************************/
  216.  
  217. SIGN_16 lne_stat()
  218. {
  219.  
  220. /* If the carrier detect bit is 1, return success (physical-connection
  221. ** still active).  Otherwise, return with a failure indication. 
  222. */
  223. if (linestat & 0x80)
  224.     return (SUCCESS);
  225. else
  226.     return (1);
  227. }
  228.  
  229. /*GLOBAL***************************************************************
  230.  
  231.     trigger_sf - initiate send framer
  232.  
  233. **********************************************************************/
  234.  
  235. void trigger_sf()
  236. {
  237.  
  238. extern USIGN_16 port_add;
  239.  
  240. /* If the RS-232 transmitter is not already busy, then a byte must 
  241. ** be placed in the transmit buffer to begin interrupt-driven sending.
  242. ** This is the start of a frame and thus the first byte to be sent is
  243. ** the SYN which begins the frame start flag.  Also the send framer's
  244. ** state variable is initialed here.
  245. */ 
  246. if (!modem_out_busy)
  247.     {
  248.     modem_out_busy = TRUE;
  249.     sf_state = SF_DLE;                
  250.     outp(port_add,SYN);
  251.     }
  252. }
  253.  
  254. /*LOCAL----------------------------------------------------------------
  255.  
  256.     get_char - get byte from send buffer
  257.  
  258. ---------------------------------------------------------------------*/
  259.  
  260. USIGN_8 get_char()
  261. {
  262.  
  263. /* Return the byte at the current send framer pointer position.
  264. ** In the process, advance the point for next time and reduce the
  265. ** number of bytes remaining by one.
  266. */
  267. sf_len--;                    
  268. return (*sf_ptr++);
  269. }
  270.  
  271. /*LOCAL----------------------------------------------------------------
  272.  
  273.     mod_stat - modem status change interrupt service routine
  274.  
  275. ---------------------------------------------------------------------*/
  276.  
  277. void mod_stat()
  278. {
  279.  
  280. /* Read modem status register and save the value.
  281. */
  282. linestat = inp(iir_add + 4);
  283.  
  284. /* If carrier has been lost, signal the mainline that the link
  285. ** also has been lost by lowering the 'link established' flag. 
  286. */
  287. if (!(linestat & 0x80))
  288.     CLRBIT1(LINK_EST)    
  289.  
  290. }
  291.  
  292. /*LOCAL----------------------------------------------------------------
  293.  
  294.     put_char - store an LT data byte
  295.  
  296. ---------------------------------------------------------------------*/
  297.  
  298. void put_char()
  299. {
  300.  
  301. /* Ignore this byte if the amount of received data exceeds the
  302. ** negotiated maximum user data size for the LT LPDU.  This could occur
  303. ** if the frame is broken or if the correspondent is misbehaving. 
  304. */
  305. if (rf_datlen >= lcb.max_data_sz)
  306.     return;
  307.  
  308. /* Otherwise, accept this byte. 
  309. */
  310. rf_datlen++;                
  311. fcscalc (&rcv_fcs, rcv_char);
  312.  
  313. /* Now store the data byte in the receive buffer using the temporary
  314. ** insert pointer.  Advance the pointer, checking for wrap.
  315. */
  316. *rf_tiptr++ = rcv_char;            
  317. if (rf_tiptr >= rbuf + RBUF_LEN)
  318.     rf_tiptr = rbuf;
  319.  
  320. }
  321.  
  322. /*LOCAL-------